package com.ruoyi.project.business.domain.rules;

import com.ruoyi.project.business.domain.entity.DailyScheduleEmp;
import com.ruoyi.project.business.domain.entity.MonthScheduleEmp;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 规则加工厂
 */
@Slf4j
public class RulesFactory {

    private boolean ruleCheckBreak = false;
    // 主要是规则冲突校验
    public void preDealRules(List<MonthScheduleEmp> emps) {
        if(CollectionUtils.isNotEmpty(emps)) {
            emps.forEach(emp -> {
                List<Rule> rules = emp.getRules();
//                List<Rule> realRules = new ArrayList<>();
                if(CollectionUtils.isNotEmpty(rules)) {
                    filterRules(rules);
                }
                emp.setRules(rules);
            });
        }
    }
    // 主要是规则冲突校验
    public void preDealRulesForDaily(List<DailyScheduleEmp> emps) {
        if(CollectionUtils.isNotEmpty(emps)) {
            emps.forEach(emp -> {
                List<Rule> rules = emp.getRules();
//                List<Rule> realRules = new ArrayList<>();
                if(CollectionUtils.isNotEmpty(rules)) {
                    filterRules(rules);
                }
                emp.setRules(rules);
            });
        }
    }


    private void filterRules(List<Rule> rules) {
        String filterRulesNames = extractRuleNames(rules);
        log.info("--------- 规则检查：{} ---------", filterRulesNames);
        for (int i = 0; i < rules.size(); i++) {
            if(ruleCheckBreak) {
                break;
            }
            Rule rule = rules.get(i);
            log.info("rule：{} ", rule.getClass().getSimpleName());
            List<Class> conflictClasses = rule.getConflicts();
            List<Rule> conflictRules = transferConflictRule(conflictClasses, rules);
            List<Rule> abandonedRules = rule.tryConflictWith(conflictRules);
            if(CollectionUtils.isEmpty(abandonedRules)) {
                log.info("规则 {} 没有冲突, i : {}, rules.size : {}", rule.getClass().getSimpleName(), i, rules.size() );
                // 表示没有冲突的规则 ，继续下一个
                if(i >= (rules.size() - 1)) {
                    // 递归的情况下，只退出当前循环回到父循环又继续了， 所以用一个标记用于退出整体
                    ruleCheckBreak = true;
                    break;
                }
            } else {
                String abandonNames = extractRuleNames(abandonedRules);
                log.info("规则 {} 与 {} 冲突, 拿掉 {}", rule.getClass().getSimpleName(),  abandonNames, abandonNames);
                // 否则移掉冲突的元素， 再递归
                rules.removeAll(abandonedRules);
                filterRules(rules);
            }

        }
    }

    private String extractRuleNames(List<Rule> abandonedRules) {
        String abandonNames = StringUtils.join(abandonedRules.stream().map(Rule::getClass).map(Class::getSimpleName).collect(Collectors.toList()), ",");
        return abandonNames;
    }

    private List<Rule> transferConflictRule(List<Class> conflicts, List<Rule> rules) {
        if(CollectionUtils.isEmpty(conflicts)) {
            return new ArrayList<>();
        }
        List<Rule> collect = new ArrayList<>();
        for (Class conflict : conflicts) {
            Rule rule = findRule(rules, conflict);
            if(rule != null) {
                collect.add(rule);
            }

        }

        return collect;
    }

    private static Rule findRule(List<Rule> rules, Class conflict) {
        for (Rule rule : rules) {
            if(rule.getClass().equals(conflict)) {
                return rule;
            }
        }
        return null;
    }

}
